<?php
/**
 * php GEM Project
 * 
 * LICENSE
 * 
 * PHP System Architecture Enabling Rapid Application Deployment and Scalability
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * @copyright Copyright (C) 2010 Zeletron LLC (http://zeletron.com)
 * @license http://gem.zeletron.com/license
 */

/*
 * GEM/Model/Domain/User.php
 * 
 * This is the user domain object. Setter methods specific
 * to this class provide a fluent interface.
 * 
 * @author David Joly
 * @link http://zeletron.com
 * 
 * @category GEM
 * @package GEM_Model
 * @subpackage GEM_Model_Domain
 * 
 */
class GEM_Model_Domain_User extends GEM_Model_Domain_Object implements Zend_Acl_Role_Interface, Zend_Acl_Resource_Interface
{	
	
	/** User Status Codes */
	const USER_STATUS_INACTIVE	= 0;
	const USER_STATUS_ACTIVE 	= 1;
	const USER_STATUS_BANNED 	= 2;
	
	/**
	 * Acl roleId (default user role is 'member')
	 * 
	 * @var string
	 */
	protected $_roleId = 'member';
	
	/**
	 * @var string
	 */
	protected $_username;
	
	/**
	 * @var string
	 */
	protected $_fullname;
	
	/**
	 * @var string
	 */
	protected $_email;
	
	/**
	 * @var string
	 */
	private $_password;
	
	/**
	 * @var Zend_Date
	 */
	protected $_createdDate;
	
	/**
	 * @var Zend_Date
	 */
	protected $_lastAccess;
	
	/**
	 * @var Zend_Date
	 */
	protected $_lastLogin;
	
	/**
	 * @var Zend_Date
	 */
	protected $_bannedDate;
	
	/**
	 * @var int
	 */
	protected $_status;
	
	/**
	 * @var string
	 */
	protected $_timezone;
	
	/**
	 * @var string
	 */
	protected $_locale;
	
	/**
	 * User's avatar
	 * 
	 * @var GEM_Model_Domain_Image
	 */
	protected $_avatar;
	
	/**
	 * @var string
	 */
	protected $_info;
	
	/**
	 * Array of social web service key => value pairs.
	 * 
	 * @var array
	 */
	protected $_social = array();
	
	/**
	 * Constructor 
	 * 
	 * @param array $fields | Optional 
	 * @return void
	 */
	public function __construct(array $fields = null)
	{
		if(!is_null($fields)){
			array_key_exists('id',$fields) ? parent::__construct($fields['id']) : parent::__construct();
			$this->_setProperties($fields);
		} else {
			parent::__construct();
		}
		$this->_safemodeExclude(array(
			'_password'
		));
	}
	
	/**
	 * Sets property values.
	 * 
	 * @param array $fields
	 * @return void
	 * @throws GEM_Model_Domain_Exception
	 */
	protected function _setProperties(array $fields)
	{
		$class = new ReflectionClass($this);
		foreach($fields as $field => $value){
			if($field != 'id'){ //ID already set in parent.
				$method = "set" . ucfirst($field);
				if(!$class->hasMethod($method))
					throw new GEM_Model_Domain_Exception("Cannot find the method {$method}().");
				$this->$method($value);
			}
		}
		unset($class);
	}
	
	/**
	 * Returns user role.
	 *
	 * @return string
	 */
	public function getRoleId()
	{
		return $this->_roleId;
	}
	
	/**
	 * Returns the resource id.
	 * 
	 * @var string
	 */
	public function getResourceId()
	{
		return 'user';
	}
	
	/**
	 * @return string
	 */
	public function getUsername()
	{
		return $this->_username;
	}
	
	/**
	 * @return string
	 */
	public function getFullname()
	{
		return $this->_fullname;
	}
	
	/**
	 * @return string
	 */
	public function getEmail()
	{
		return $this->_email;
	}
	
	/**
	 * @return string
	 */
	public function getPassword()
	{
		return $this->_password;
	}
	
	/**
	 * @param boolean $returnZendDate
	 * @return mixed string | Zend_Date
	 */
	public function getCreatedDate($returnZendDate = false)
	{
		return $returnZendDate === true 
			? new Zend_Date($this->_createdDate, Zend_Date::ISO_8601)
			: $this->_createdDate;
	}
	
	/**
	 * @return string
	 */
	public function getLastAccess()
	{
		return $this->_lastAccess;
	}
	
	/**
	 * @return string
	 */
	public function getLastLogin()
	{
		return $this->_lastLogin;
	}
	
	/**
	 * @return string
	 */
	public function getBannedDate()
	{
		return $this->_bannedDate;
	}
	
	/**
	 * @return int
	 */
	public function getStatus()
	{
		return $this->_status;
	}
	
	/**
	 * @return string
	 */
	public function getTimezone()
	{
		return $this->_timezone;
	}
	
	/**
	 * @return string
	 */
	public function getLocale()
	{
		return $this->_locale;
	}
	
	/**
	 * Initializes and returns the user's
	 * avatar as an image object.
	 * 
	 * @return GEM_Model_Domain_Image
	 */
	public function getAvatar()
	{
		if(! ($this->_avatar instanceof GEM_Model_Domain_Image)){
			return GEM_Model_Domain_Image::getFinder('Image')->find(1); //Default avatar file id is 1
		}
		return $this->_avatar;
	}
	
	/**
	 * @return string
	 */
	public function getInfo()
	{
		return $this->_info;
	}
	
	/**
	 * @param string $type | optional The social type (i.e. facebook)
	 * @return array
	 */
	public function getSocial($type = null)
	{
		if(!is_null($type))
			return array_key_exists($type,$this->_social) ? $this->_social[$type] : null;
		return $this->_social;
	}
	
	/**
	 * Sets user's roleId
	 * 
	 * @param string
	 * @return GEM_Model_Domain_User Enables a Fluent Interface
	 */
	public function setRoleId($roleId)
	{
		if(!is_null($this->_roleId)) $this->_markPropertyAsChanged('roleId');
		$this->_roleId = (string)$roleId;
		return $this;
	}
	
	/**
	 * @param string $username
	 * @return GEM_Model_Domain_User Enables a Fluent Interface
	 */
	public function setUsername($username)
	{
		if(!is_null($this->_username)) $this->_markPropertyAsChanged('username');
		$this->_username = (string)$username;
		return $this;
	}
	
	/**
	 * @param string $fullname
	 * @return GEM_Model_Domain_User Enables a Fluent Interface
	 */
	public function setFullname($fullname)
	{
		if(!is_null($this->_fullname)) $this->_markPropertyAsChanged('fullname');
		$this->_fullname = (string)$fullname;
		return $this;
	}
	
	/**
	 * @param string $email
	 * @return GEM_Model_Domain_User Enables a Fluent Interface
	 */
	public function setEmail($email)
	{
		if(!is_null($this->_email)) $this->_markPropertyAsChanged('email');
		$this->_email = (string)$email;
		return $this;
	}
	
	/**
	 * When setting the password property, raw passwords
	 * must be encrypted using crypt().
	 * 
	 * @param $password
	 * @return GEM_Model_Domain_User Enables a Fluent Interface
	 */
	public function setPassword($password)
	{
		if(!is_null($this->_password))$this->_markPropertyAsChanged('password');
		$this->_password = $password;	
		return $this;
	}
	
	/** 
	 * @param string $date
	 * @return GEM_Model_Domain_User Enables a Fluent Interface
	 * @uses Zend_Date
	 * @throws GEM_Model_Domain_Exception
	 */
	public function setCreatedDate($date)
	{
		if(!Zend_Date::isDate($date,'Y-m-d H:i:s'))
			throw new GEM_Model_Domain_Exception('Invalid datetime value.');
		if(!is_null($this->_createdDate)) $this->_markPropertyAsChanged('createdDate');
		$this->_createdDate = $date;
		return $this;
	}
	
	/** 
	 * @param string $date
	 * @return GEM_Model_Domain_User Enables a Fluent Interface
	 * @uses Zend_Date
	 * @throws GEM_Model_Domain_Exception
	 */
	public function setLastAccess($date)
	{
		if(!Zend_Date::isDate($date,'Y-m-d H:i:s'))
			throw new GEM_Model_Domain_Exception('Invalid date value.');
		if(!is_null($this->_lastAccess)) $this->_markPropertyAsChanged('lastAccess');
		$this->_lastAccess = $date;
		return $this;
	}
	
	/** 
	 * @param string $date
	 * @return GEM_Model_Domain_User Enables a Fluent Interface
	 * @uses Zend_Date
	 * @throws GEM_Model_Domain_Exception
	 */
	public function setLastLogin($date)
	{
		if(!Zend_Date::isDate($date,'Y-m-d H:i:s'))
			throw new GEM_Model_Domain_Exception('Invalid date value.');
		if(!is_null($this->_lastLogin)) $this->_markPropertyAsChanged('lastLogin');
		$this->_lastLogin = $date;
		return $this;
	}
	
	/** 
	 * @param string $date
	 * @return GEM_Model_Domain_User Enables a Fluent Interface
	 * @uses Zend_Date
	 * @throws GEM_Model_Domain_Exception
	 */
	public function setBannedDate($date)
	{
		if(!Zend_Date::isDate($date,'Y-m-d H:i:s') && $date != '0000-00-00 00:00:00')
			throw new GEM_Model_Domain_Exception('Invalid date value.');
		if(!is_null($this->_bannedDate)) $this->_markPropertyAsChanged('bannedDate');
		$this->_bannedDate = $date;
		return $this;
	}
	
	/** 
	 * @param int $status
	 * @return GEM_Model_Domain_User Enables a Fluent Interface
	 */
	public function setStatus($status)
	{
		if((int)$status != self::USER_STATUS_INACTIVE && (int)$status != self::USER_STATUS_ACTIVE && (int)$status != self::USER_STATUS_BANNED)
			throw new GEM_Model_Domain_Exception('Invalid status value.');
		if(isset($this->_status)) $this->_markPropertyAsChanged('status');
		$this->_status = $status;
		return $this;
	}
	
	/**
	 * @param string $timezone
	 * @return GEM_Model_Domain_User Enables a Fluent Interface
	 * @throws GEM_Model_Domain_Exception
	 */
	public function setTimezone($timezone)
	{
		$timezones = DateTimeZone::listIdentifiers();
		if(!in_array($timezone,$timezones))
			throw new GEM_Model_Domain_Exception('Invalid timezone value.');
		if(!is_null($this->_timezone)) $this->_markPropertyAsChanged('timezone');
		$this->_timezone = $timezone;
		return $this;
	}
	
	/**
	 * @param string $locale
	 * @return GEM_Model_Domain_User Enables a Fluent Interface
	 * @throws GEM_Model_Domain_Exception
	 * @uses Zend_Locale
	 */
	public function setLocale($locale)
	{
		if(!Zend_Locale::isLocale($locale))
			throw new GEM_Model_Domain_Exception('Invalid locale value.');
		if(!is_null($this->_locale)) $this->_markPropertyAsChanged('locale');
		$this->_locale = (string)$locale;
		return $this;
	}
	
	/**
	 * @param int|GEM_Model_Domain_Image $avatar
	 * @return GEM_Model_Domain_User Enables a Fluent Interface
	 * @throws GEM_Model_Domain_Exception
	 */
	public function setAvatar($avatar)
	{
		if(!is_null($this->_avatar)) $this->_markPropertyAsChanged('avatar');
		if($avatar instanceof GEM_Model_Domain_Image) { 
			$this->_avatar = $avatar; 
		} else if(is_numeric($avatar)) { 
			$this->_avatar = GEM_Model_Domain_Image::getFinder('Image')->find((int)$avatar); 
		} else { 
			throw new GEM_Model_Domain_Exception(__METHOD__ . " expects either a numerical id value or a GEM_Model_Domain_Image object.");
		}
		return $this;
	}
	
	/**
	 * @param string $info
	 * @return GEM_Model_Domain_User Enables a Fluent Interface
	 */
	public function setInfo($info)
	{
		if(!is_null($this->_info)) $this->_markPropertyAsChanged('info');
		$this->_info = (string)$info;
		return $this;
	}
	
	/**
	 * @param mixed array | string $social  array or serialized array
	 * @return GEM_Model_Domain_User Enables a Fluent Interface
	 * @throws GEM_Model_Domain_Exception
	 */
	public function setSocial($social)
	{
		if(empty($social)) { //Ignoring null values
			return $this;
		}
		if(!is_array($social)){
			//Is it a serialized array?
			if(is_string($social)){
				$social = unserialize($social);				
			}
			if(!is_array($social) && !is_null($social))
				throw new GEM_Model_Domain_Exception(__METHOD__ . " expects an array or serialized array.");
		}
		if(!is_null($this->_social) && $this->_social != $social) $this->_markPropertyAsChanged('social');
		$this->_social = $social;
		return $this;
	}
	
	/**
	 * @return boolean
	 */
	public function hasInfo()
	{
		return (is_null($this->_info) || trim($this->_info) == '') ? false : true;
			
	}
	
	/**
	 * @param $type | optional
	 * @return boolean
	 */
	public function hasSocial($type = null)
	{
		if(!is_null($type)) return array_key_exists($type, $this->_social);
		return count($this->_social) == 0 ? false : true;
			
	}
	
	/**
	 * @param string $type
	 * @param string $value
	 * @return GEM_Model_Domain_User | Enables a Fluent Interface
	 * @throws GEM_Model_Domain_Exception
	 */
	public function addSocial($type, $value)
	{
		$socialTypes = Zend_Registry::get('config')->accounts->socialTypes->toArray();
		if(!in_array($type,$socialTypes))
			throw new GEM_Model_Domain_Exception("Application not configured for social type $type. Check your configuration file.");
		$this->_social[$type] = $value;
		$this->_markPropertyAsChanged('social');
		return $this;
	}
}